#ifndef __VECTOR3_H__
#define __VECTOR3_H__

#include "Math.h"

template<class Real>
class Vector3
{
public:
	// Construction
	Vector3<Real>();
	Vector3<Real>( Real fx, Real fy, Real fz );
	Vector3<Real>( Real coordianate[3] );
	Vector3<Real>( const Vector3& vec );

	// operators
	Real x, y, z;
	Real& operator[] ( int i ) const;
	operator Real* ();

	// assignment and comparison
	Vector3<Real>& operator= ( const Vector3<Real>& vec );
	bool operator== ( const Vector3<Real>& vec ) const;
	bool operator!= ( const Vector3<Real>& vec ) const;

	Vector3<Real>& operator + ( const Vector3<Real>& vec ) const;
	Vector3<Real>& operator - ( const Vector3<Real>& vec ) const;
	Vector3<Real>& operator * ( Real scalar ) const;
	Vector3<Real>& operator / ( Real scalar ) const;
	Vector3<Real>& operator - () const;
	template<class Real>
	void mult( Real scalar, const Vector3<Real>& vector )const;

	// arithmetic updates
    Vector3<Real>& operator+= ( const Vector3<Real>& vector )const;
    Vector3<Real>& operator-= ( const Vector3<Real>& vector )const;
    Vector3<Real>& operator*= ( const Vector3<Real>& vector )const;
    Vector3<Real>& operator/= ( Real fscalar );
	
    // vector operations
    Real length () const;
    Real squared_length () const;
    Real dot ( const Vector3& vector ) const;
    Real unitize ( Real tolerance = 1e-06 );
    Vector3<Real> cross ( const Vector3<Real>& vector ) const;
    Vector3<Real> unit_cross ( const Vector3<Real>& vector ) const;

    // Gram-Schmidt orthonormalization.
    static void orthonormalize ( Vector3<Real> vector[3] );

    // Input W must be initialize to a nonzero vector, output is {U,V,W}
    // an orthonormal basis.  A hint is provided about whether or not W
    // is already unit length.
    static void generate_orthonormal_basis ( Vector3<Real>& u, Vector3<Real>& v,
        Vector3<Real>& w, bool unit_length = true);

    // special points
    static const Vector3<Real> ZERO;
    static const Vector3<Real> UNIT_X;
    static const Vector3<Real> UNIT_Y;
    static const Vector3<Real> UNIT_Z;
};

//template class Vector3<float>;
//Vector3<float> Vector3<float>::operator*( float scalar, const Vector3<float>& vec) const;
#endif
